﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using MahApps.Metro.Controls;
using MahApps.Metro.Controls.Dialogs;
using ControlzEx.Theming;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.Diagnostics;
using System.Data;
using System.IO;
using System.Windows.Threading;
using Newtonsoft.Json;
using System.Reflection;
using Newtonsoft.Json.Linq;

namespace WpfBeyond
{
    /// <summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>
    public partial class MainWindow : MetroWindow
    {
        IOCP iocp_dev = null;     //D协议长连接
        IOCP iocp_reback = null; //E协议短连接

        private DispatcherTimer readDataTimer = null;

        private static DateTime dt = DateTime.MinValue;

        public void timeCycle(object sender, EventArgs e)
        {
            TaskInfo t = null;
            
            try
            {
                t = TaskFactory.GetPlayTask();
                if (t != null)
                {
                    t.Start();
                }

                t = TaskFactory.GetStopTask();
                if (t != null)
                {
                    t.Stop();
                    Common.reflash_task = true;
                }

                TaskFactory.Check_TaskInfo();
                TaskFactory.DelExpireTask();

                //2分钟广播一次
                if (dt.Subtract(DateTime.Now).Duration().TotalMinutes > 1)
                {
                    dt = DateTime.Now;
                    BroadCast();
                }

            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.Message);
            }
        }

        private void Output(object sendProcess, DataReceivedEventArgs output)
        {
            if (!String.IsNullOrEmpty(output.Data))
            {
                LogHelp.Info(output.Data);

                //[dshow @ 0000000000572300]  "Mic in at front panel (Pink) (R"
                if (output.Data.IndexOf("[dshow @") >= 0 && output.Data.IndexOf("\"") >= 0 && output.Data.IndexOf("Alternative name") == -1)
                {
                    string device_name = output.Data.Substring(output.Data.IndexOf("\"") + 1, output.Data.LastIndexOf("\"") - output.Data.IndexOf("\"") - 1);
                    audio_device_name dev = new audio_device_name();
                    dev.Name = device_name;
                    dev.Value = device_name;
                    Common.audio_device_list.Add(dev);
                }
            }
        }
        
        private void BroadCast()
        {            

            //只能用UDP协议发送广播，所以ProtocolType设置为UDP
            Socket socket = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp);
            //让其自动提供子网中的IP地址
            IPEndPoint iep = new IPEndPoint(IPAddress.Broadcast, 23025);
            //设置broadcast值为1，允许套接字发送广播信息
            socket.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Broadcast, 1);
            //将发送内容转换为字节数组
            JObject json = new JObject();
            json["server_port"] = LocalSetting.Items.Server_port;
            json["reback_port"] = LocalSetting.Items.Reback_port;

            byte[] bytes = System.Text.Encoding.Unicode.GetBytes(json.ToString());
            //向子网发送信息
            socket.SendTo(bytes, iep);
            socket.Close();
        }

        private void GetAudioDeviceName()
        {
            Process p = new Process();

            string FFmpegPath = @"ffmpeg.exe";
            p.StartInfo.FileName = FFmpegPath;

            //ffmpeg -fflags nobuffer -f dshow -i audio="Mic in at rear panel(Pink)" -acodec aac -f flv rtmp://localhost:1935/live/test1
            string para = string.Format("ffmpeg -list_devices true -f dshow -i dummy");

            p.StartInfo.Arguments = para;

            //是否使用操作系统shell启动
            p.StartInfo.UseShellExecute = false;
            //不显示程序窗口
            p.StartInfo.CreateNoWindow = true;

            p.StartInfo.RedirectStandardError = true;//把外部程序错误输出写到StandardError流中(这个一定要注意,FFMPEG的所有输出信息,都为错误输出流
            p.ErrorDataReceived += new DataReceivedEventHandler(Output);//外部程序(这里是FFMPEG)输出流时候产生的事件,这里是把流的处理过程转移到下面的方法中,详细请查阅MSDN            

            p.Start();

            p.BeginErrorReadLine();//开始异步读取 
        }

        public MainWindow()
        {
            InitializeComponent();

            try
            {
                GetAudioDeviceName();

                try
                {
                    //从文本从反序列化任务信息                
                    TaskFactory.list = Common.LoadTaskJson();
                    if (TaskFactory.list == null)
                    {
                        TaskFactory.list = new List<TaskInfo>();
                    }

                    //载入设置信息
                    LocalSetting.Items = Common.LoadSettingJson();
                    if(LocalSetting.Items == null)
                    {
                        LocalSetting.Items = new SettingItem();
                    }
                    else
                    {
                        LogHelp.ClearLog(LocalSetting.Items.Savelog_days);
                    }

                    //载入设备信息
                    Devices.list = Common.LoadDevicesJson();
                    if (Devices.list == null)
                    {
                        Devices.list = new List<Device>();
                    }
                    
                }
                catch (Exception ex)
                {
                    //不处理
                }

                //监听客户端的IOCP
                iocp_dev = new IOCP("D协议", LocalSetting.Items.Server_port);
                iocp_dev.RecvCallBack += new IOCP.RecvDataHandler(iocp_dev_RecvCallBack);
                iocp_dev.CloseSocketCallBack += new IOCP.CloseSocketHandler(iocp_client_CloseSocketCallBack);

                iocp_reback = new IOCP("E协议", LocalSetting.Items.Reback_port);
                iocp_reback.RecvCallBack += new IOCP.RecvDataHandler(iocp_dev_RebackCallBack);
                iocp_reback.CloseSocketCallBack += new IOCP.CloseSocketHandler(iocp_client_CloseRebackCallBack);

                Common.LoadingCallBack += Common_LoadingCallBack;

                if (readDataTimer == null)
                {
                    readDataTimer = new DispatcherTimer();//定时器 ;
                    readDataTimer.Tick += new EventHandler(timeCycle);
                    readDataTimer.Interval = new TimeSpan(0, 0, 0, 0, 500);
                }

                readDataTimer.Start();
            }
            catch (Exception ex)
            {
                MessageBox.Show(ex.ToString());
            }

        }

        private void Common_LoadingCallBack(bool Active)
        {
            if (progressring.Dispatcher.CheckAccess())
            {
                progressring.IsActive = Active;                
            }
            else
            {
                progressring.Dispatcher.BeginInvoke(
                  DispatcherPriority.Normal,
                  new Action(() =>
                  {
                      progressring.IsActive = Active;                      
                  }));
            }
        }

        /// <summary>
        /// D协议连接断开处理
        /// </summary>
        /// <param name="s"></param>
        private void iocp_client_CloseSocketCallBack(Socket s)
        {
            int i = 0;
            try
            {
                for (i = 0; i < Devices.list.Count; i++)
                {
                    if (Devices.list[i].socket == s)
                    {
                        Devices.list[i].socket = null;
                        Devices.list[i].Status = 0;
                        break;
                    }
                }
            }
            catch (Exception ex)
            {
                LogHelp.Error(ex.ToString());
            }
        }

        /// <summary>
        /// E协议连接断开回调处理
        /// </summary>
        /// <param name="s"></param>
        private void iocp_client_CloseRebackCallBack(Socket s)
        {
            int i = 0;
            try
            {
                //for (i = 0; i < devices.Count; i++)
                //{

                //}
            }
            catch (Exception ex)
            {
                LogHelp.Error(ex.ToString());
            }
        }

        private void iocp_dev_RecvCallBack(Socket s, byte[] b, int len)
        {
            //JObject json = null;
            int n = 0;
            int pos = 0;

            string str = "";
            int i = 0;
            StringBuilder sb = new StringBuilder();

            if (s == null)
            {
                LogHelp.Error("CLIENT SOCKET IS NULL!");
                return;
            }

            try
            {
                sb.Remove(0, sb.Length);
                for (i = 0; i < len; i++)
                {
                    sb.Append(b[i].ToString("X2"));
                }
                LogHelp.Info("RECV [" + s.RemoteEndPoint.ToString() + "] : " + sb.ToString());

                IpPacket packet = new IpPacket();

                packet.Parse(b);

                if (packet.body.type == 0x10)
                {
                    IPEndPoint ipe = (IPEndPoint)s.RemoteEndPoint;

                    string ip = ipe.Address.ToString();
                    int port = ipe.Port;

                    Device d = new Device();
                    d.ipaddr = ip;
                    d.port = port;
                    d.socket = s;
                    d.Status = (int)packet.body.p_heartbeat.status;
                    d.reg = (int)packet.body.p_heartbeat.firstReg;
                    d.SerialNo = packet.body.p_heartbeat.sn;
                    d.Resource_code = Common.BCD2STR(packet.body.src_obj, 12);

                    proc_heartbeat(d);
                }

                //只有针对请求包才发送一般应答包
                if (packet.head.type == 0x1)
                {
                    packet.packet();
                    s.Send(packet.data, packet.data_len, SocketFlags.None);

                    sb.Remove(0, sb.Length);
                    for (i = 0; i < packet.data_len; i++)
                    {
                        sb.Append(packet.data[i].ToString("X2"));
                    }
                    LogHelp.Info("SEND [" + s.RemoteEndPoint.ToString() + "] : " + sb.ToString());
                }
            }
            catch (Exception ex)
            {
                LogHelp.Error(ex.ToString() + "str:" + str);
            }
        }

        /// <summary>
        /// E协议的回调处理
        /// </summary>
        /// <param name="s"></param>
        /// <param name="b"></param>
        /// <param name="len"></param>
        private void iocp_dev_RebackCallBack(Socket s, byte[] b, int len)
        {
            //JObject json = null;
            int n = 0;
            int pos = 0;

            string str = "";
            int i = 0;
            StringBuilder sb = new StringBuilder();

            if (s == null)
            {
                LogHelp.Error("CLIENT SOCKET IS NULL!");
                return;
            }

            try
            {
                sb.Remove(0, sb.Length);
                for (i = 0; i < len; i++)
                {
                    sb.Append(b[i].ToString("X2"));
                }
                LogHelp.Info("RECV E[" + s.RemoteEndPoint.ToString() + "] : " + sb.ToString());

                RebackPacket packet = new RebackPacket();

                packet.Parse(b);

                if (packet.body.type == 0x10)
                {
                    //IPEndPoint ipe = (IPEndPoint)s.RemoteEndPoint;

                    //string ip = ipe.Address.ToString();
                    //int port = ipe.Port;

                    //Device d = new Device();
                    //d.ipaddr = ip;
                    //d.port = port;
                    //d.socket = s;
                    //d.Status = (int)packet.body.heartbeat.status;
                    //d.reg = (int)packet.body.heartbeat.firstReg;
                    //d.SerialNo = packet.body.heartbeat.sn;
                    //d.Resource_code = Common.BCD2STR(packet.body.src_obj, 12);

                    //proc_heartbeat(d);
                }
                else if (packet.body.type == 0x11)
                {
                    Device d = Devices.Get_Device_byCode(Common.BCD2STR(packet.body.src_obj, 12));

                    if (d == null) return;

                    foreach (param_info param in packet.body.query.param_tag_list)
                    {
                        if (param.Tag == 0x1)//终端音量
                        {
                            d.volume = param.content[0];
                        }
                        else if (param.Tag == 0x2)//本地地址
                        {
                            byte[] ipaddr = new byte[4];
                            Array.Copy(param.content, 0, ipaddr, 0, 4);
                            d.Local_ip = Common.BCD2IP(ipaddr, 4);

                            Array.Copy(param.content, 4, ipaddr, 0, 4);
                            d.Local_mask = Common.BCD2IP(ipaddr, 4);

                            Array.Copy(param.content, 8, ipaddr, 0, 4);
                            d.Local_gw = Common.BCD2IP(ipaddr, 4);
                        }
                        else if (param.Tag == 0x3)//回传地址
                        {
                            d.reback_type = param.content[0];

                            if (d.reback_type == 1)//IP地址
                            {
                                sb.Remove(0, sb.Length);
                                sb.Append(param.content[1].ToString());
                                sb.Append(".");
                                sb.Append(param.content[2].ToString());
                                sb.Append(".");
                                sb.Append(param.content[3].ToString());
                                sb.Append(".");
                                sb.Append(param.content[4].ToString());
                                sb.Append(":");
                                sb.Append((UInt16)(param.content[5] * 256 + param.content[6]));
                                d.reback_param = sb.ToString();
                            }
                            else if (d.reback_type == 2)//域名
                            {

                            }
                            else if (d.reback_type == 3)//手机
                            {

                            }
                        }
                        else if (param.Tag == 0x4)
                        {
                            d.Resource_code = Common.BCD2STR(param.content, 12);
                        }
                        else if (param.Tag == 0x5)//物理地址编码
                        {
                            sb.Remove(0, sb.Length);
                            for (i = 1; i < param.len; i++)
                            {
                                sb.Append(param.content[i].ToString("X2"));
                            }
                            d.serialNo = sb.ToString();
                        }
                        else if (param.Tag == 0x6)
                        {
                            d.Status = param.content[0];
                        }
                        else if (param.Tag == 0x7)
                        {
                            d.errCode = param.content[0];
                        }
                        else if (param.Tag == 0x8)
                        {
                            d.device_type = param.content[0].ToString("D2") + " " + param.content[1].ToString("D2");
                        }
                        else if (param.Tag == 0x9)
                        {
                            sb.Remove(0, sb.Length);
                            for (i = 0; i < param.len; i++)
                            {
                                sb.Append(param.content[i].ToString("X2"));
                                if (i < param.len - 1)
                                {
                                    sb.Append(".");
                                }
                            }

                            d.Hardware = sb.ToString();
                        }
                        else if (param.Tag == 0xA)
                        {
                            sb.Remove(0, sb.Length);
                            for (i = 0; i < param.len; i++)
                            {
                                sb.Append(param.content[i].ToString("X2"));
                                if (i < param.len - 1)
                                {
                                    sb.Append(".");
                                }
                            }

                            d.Software = sb.ToString();
                        }
                    }

                    Devices.Update_Device(d);

                    //添加更新的标识
                    foreach (param_info param in packet.body.query.param_tag_list)
                    {
                        lock (d.lock_user)
                        {
                            d.ReflashTagList.Add(param.Tag);
                        }
                    }

                }

                //只有针对请求包才发送一般应答包
                if (packet.head.type == 0x1)
                {
                    //packet.packet();
                    //s.Send(packet.data, packet.data_len, SocketFlags.None);

                    //sb.Remove(0, sb.Length);
                    //for (i = 0; i < packet.data_len; i++)
                    //{
                    //    sb.Append(packet.data[i].ToString("X2"));
                    //}
                    //LogHelp.Info("SEND E[" + s.RemoteEndPoint.ToString() + "] : " + sb.ToString());
                }
            }
            catch (Exception ex)
            {
                LogHelp.Error(ex.ToString() + "str:" + str);
            }
        }

        private void proc_heartbeat(Device d)
        {
            if (Devices.Add_Device(d))
            {
                Common.reflash_device = true;
            }
        }

        private void Logo_Click(object sender, RoutedEventArgs e)
        {
            //TODO:
        }

        private void copyright(object sender, RoutedEventArgs e)
        {
            fo_about.IsOpen = true;
        }

        private async void MetroWindow_Closing(object sender, System.ComponentModel.CancelEventArgs e)
        {
            bool HaveProcess = false;

            foreach (TaskInfo t in TaskFactory.list)
            {
                if (t.process != null)
                {
                    try
                    {
                        if (t.process.HasExited == false)
                        {
                            HaveProcess = true;
                            e.Cancel = true;
                            break;
                        }
                    }
                    catch (Exception ex)
                    {
                        //不处理
                    }

                }
            }

            if (HaveProcess == true)
            {
                MessageDialogResult result = await this.ShowMessageAsync("提示", "系统还有未结束的广播任务！要全部停止吗？", MessageDialogStyle.AffirmativeAndNegative);
                if (result == MessageDialogResult.Affirmative)
                {
                    TaskFactory.StopAll();
                    this.Close();
                }
                else
                {
                    e.Cancel = true;
                }
            }

            //保存任务信息
            Common.SaveJson(LocalSetting.taskinfo_JsonFileName, TaskFactory.list);           

            //保存设备信息
            Common.SaveJson(LocalSetting.devices_JsonFileName, Devices.list);
           
        }

    }

}
